#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
#include "shmem.h"
#include "MQTTClient.h"
#include <pthread.h>

#define ADDRESS "tcp://192.168.0.159:1883"
#define CLIENTID "linuxGateway"
// 指令控制  Qt->Linux 
#define  COMMAND_CONTROL_TOPIC "DataSubmitProcess/CommandControl"
// 设备状态上报 Linux->QT
#define  DEVICES_STATA_TOPIC "DataSubmitProcess/DevicesStata"

#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
#define isOpenDebug 1
// 控制多长时间发送一次
#define UPDADA_DURATION 3


typedef struct
{
    int key;
    char name[32];
    int type;
    int typeStata;
    int value;
    float floatValue;
} Stm32Data;

typedef struct
{
    int key;
    char name[32];
    int addr;
    int type;
    int typeStata;
    int value;
} ModbusData;

typedef struct
{
    int key;
    char name[32];
    int type;
    int typeStata;
    int addr;
    int value;
} MetaServerData;

typedef struct
{
    Stm32Data *stm32_list;
    int stm32_count;
    ModbusData *modbus_list;
    int modbus_count;
    MetaServerData *meta_list;
    int meta_count;
} DeviceData;

/**
 * @brief 打印错误信息
 *
 */
void printError(int lineNumber)
{
#if isOpenDebug
    printf("----------------------%d\n", lineNumber);
#endif
}

volatile MQTTClient_deliveryToken deliveredtoken;

DeviceData *device = NULL;


void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}

/**
 * @brief 消息接收回调函数
 *
 */
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    int i;
    char *payloadptr;

    printf("Message arrived\n");
    printf("     topic: %s\n", topicName);
    printf("   message: ");

    payloadptr = message->payload;
    for (i = 0; i < message->payloadlen; i++)
    {
        putchar(*payloadptr++);
    }
    putchar('\n');

    cJSON *root = cJSON_Parse((char *)message->payload);

    if (root == NULL)
    {
        printf("parse json failed\n");
        return -1;
    }
    cJSON *name = cJSON_GetObjectItem(root, "name");
    printf("name is : %s\n", name->valuestring);
    cJSON *age = cJSON_GetObjectItem(root, "age");
    printf("age is : %d\n", age->valueint);
    cJSON *msg = cJSON_GetObjectItem(root, "msg");
    printf("msg is : %s\n", msg->valuestring);

    // 释放内存
    cJSON_Delete(root);

    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);

    return 1;
}

/**
 * @brief 连接丢失回调函数
 *
 */
void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}

/**
 * @brief 解析stm32数据
 *
 */

static int parse_stm32(cJSON *stm32_obj, DeviceData *device)
{

    cJSON *data_array = cJSON_GetObjectItem(stm32_obj, "data");

    // 获取数组长度，分配结构体数组内存
    device->stm32_count = cJSON_GetArraySize(data_array);
    device->stm32_list = (Stm32Data *)malloc(sizeof(Stm32Data) * device->stm32_count);
    if (!device->stm32_list)
    {
        printf("malloc stm32_list failed\n");
        return -1;
    }

    // 遍历数组，填充每个结构体
    for (int i = 0; i < device->stm32_count; i++)
    {
        cJSON *item = cJSON_GetArrayItem(data_array, i);

        Stm32Data *stm = &device->stm32_list[i];

        // 解析必选字段（若字段不存在，用默认值或报错）
        cJSON *key = cJSON_GetObjectItem(item, "key");
        stm->key = key->valueint;

        cJSON *name = cJSON_GetObjectItem(item, "name");
        strncpy(stm->name, name->valuestring, sizeof(stm->name) - 1);

        cJSON *type = cJSON_GetObjectItem(item, "type");
        stm->type = type->valueint;

        cJSON *typeStata = cJSON_GetObjectItem(item, "typeStata");
        stm->typeStata = typeStata->valueint;

        cJSON *value = cJSON_GetObjectItem(item, "value");
        stm->value = value->valueint;

        printError(__LINE__);
        // floatVale
        cJSON *floatValue = cJSON_GetObjectItem(item, "floatValue");
        stm->floatValue = floatValue->valuedouble;
        printError(__LINE__);
    }

    return 0;
}

/**
 * @brief 解析modbus数据
 *
 */

static int parse_modbus(cJSON *modbus_obj, DeviceData *device)
{

    cJSON *data_array = cJSON_GetObjectItem(modbus_obj, "data");

    device->modbus_count = cJSON_GetArraySize(data_array);
    device->modbus_list = (ModbusData *)malloc(sizeof(ModbusData) * device->modbus_count);

    if (!device->modbus_list)
    {
        printf("malloc modbus_list failed\n");
        return -1;
    }

    for (int i = 0; i < device->modbus_count; i++)
    {

        cJSON *item = cJSON_GetArrayItem(data_array, i);
        ModbusData *modbus = &device->modbus_list[i];

        cJSON *key = cJSON_GetObjectItem(item, "key");
        modbus->key = key->valueint;

        cJSON *name = cJSON_GetObjectItem(item, "name");
        strncpy(modbus->name, name->valuestring, sizeof(modbus->name) - 1);

        cJSON *addr = cJSON_GetObjectItem(item, "addr");
        modbus->addr = addr->valueint;

        cJSON *type = cJSON_GetObjectItem(item, "type");
        modbus->type = type->valueint;

        cJSON *typeStata = cJSON_GetObjectItem(item, "typeStata");

        modbus->typeStata = typeStata->valueint;
        cJSON *value = cJSON_GetObjectItem(item, "value");

        modbus->value = value->valueint;
    }
    return 0;
}

/**
 * @brief 解析元宇宙数据
 *
 */

static int parse_metaserver(cJSON *meta_obj, DeviceData *device)
{
    cJSON *data_array = cJSON_GetObjectItem(meta_obj, "data");

    device->meta_count = cJSON_GetArraySize(data_array);
    device->meta_list = (MetaServerData *)malloc(sizeof(MetaServerData) * device->meta_count);
    if (!device->meta_list)
    {
        printf("malloc meta_list failed\n");
        return -1;
    }

    for (int i = 0; i < device->meta_count; i++)
    {
        cJSON *item = cJSON_GetArrayItem(data_array, i);
        MetaServerData *meta = &device->meta_list[i];

        // 必选字段解析（参考stm32的解析逻辑）
        cJSON *key = cJSON_GetObjectItem(item, "key");
        meta->key = key->valueint;

        cJSON *name = cJSON_GetObjectItem(item, "name");
        strncpy(meta->name, name->valuestring, sizeof(meta->name) - 1);

        cJSON *type = cJSON_GetObjectItem(item, "type");
        meta->type = type->valueint;

        cJSON *typeStata = cJSON_GetObjectItem(item, "typeStata");
        meta->typeStata = typeStata->valueint;

        cJSON *addr = cJSON_GetObjectItem(item, "addr");
        meta->addr = addr->valueint;
    }
    return 0;
}

/**
 * @brief 解析json数据并映射到内存

 *
*/
DeviceData *device_data_init(const char *json_str)
{

     device = (DeviceData *)calloc(1, sizeof(DeviceData)); // 初始化为0
    if (!device)
        return NULL;

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
        printf("parse json failed: %s\n", cJSON_GetErrorPtr());
        free(device);
        return NULL;
    }

    // 分别解析三大块数据
    cJSON *stm32_obj = cJSON_GetObjectItem(root, "stm32");

    if (stm32_obj && parse_stm32(stm32_obj, device) != 0)
    {
        goto error;
    }

    cJSON *modbus_obj = cJSON_GetObjectItem(root, "modbus");

    if (modbus_obj && parse_modbus(modbus_obj, device) != 0)
    {
        goto error;
    }

    cJSON *meta_obj = cJSON_GetObjectItem(root, "metaServer");

    if (meta_obj && parse_metaserver(meta_obj, device) != 0)
    {
        goto error;
    }

    cJSON_Delete(root);
    return device;

error:
    // 解析失败时释放已分配的内存
    free(device->stm32_list);
    free(device->modbus_list);
    free(device->meta_list);
    free(device);
    cJSON_Delete(root);
    return NULL;
}

// 释放设备数据内存
void device_data_free(DeviceData *device)
{
    if (device)
    {
        free(device->stm32_list);
        free(device->modbus_list);
        free(device->meta_list);
        free(device);
    }
}

/**
 * @brief 打开配置文件
 *
 */
char *openConfigFile(char const *jsonPath)
{
    // 1. 读取JSON文件（参考之前的文件读取逻辑）
    FILE *fp = fopen(jsonPath, "r");
    if (!fp)
    {
        printf("open file failed\n");
        return NULL;
    }

    fseek(fp, 0, SEEK_END);
    long file_size = ftell(fp);
    rewind(fp);
    char *buf = (char *)malloc(file_size + 1);
    fread(buf, 1, file_size, fp);
    buf[file_size] = '\0';
    fclose(fp);

    return buf;
}

/**
 * @brief 启动mqtt客户端
 *
 */
int startCommitByMQTT()
{
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    int rc;
    int ch;
    MQTTClient_deliveryToken token;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;

    MQTTClient_create(&client, ADDRESS, CLIENTID,
                      MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q<Enter> to quit\n\n",
           COMMAND_CONTROL_TOPIC, CLIENTID, QOS);

    MQTTClient_subscribe(client, COMMAND_CONTROL_TOPIC, QOS);

    

while (1)
{
    // 控制多长时间发送一次
    sleep(UPDADA_DURATION);


    cJSON *root = cJSON_CreateObject();
    Stm32Data *stm32 = device->stm32_list;
    // stm32 json
    cJSON *stm32Arry = cJSON_CreateArray();
    for (size_t i = 0; i < device->stm32_count; i++)
    {
        
       cJSON *obj = cJSON_CreateObject();

       cJSON *keyValue =   cJSON_CreateNumber(device->stm32_list[i].key);
       cJSON_AddItemToObject(obj,"key",keyValue);

       cJSON *nameValue =   cJSON_CreateString(device->stm32_list[i].name);
       cJSON_AddItemToObject(obj,"name",nameValue);

       cJSON *typeValue =   cJSON_CreateNumber(device->stm32_list[i].type);
       cJSON_AddItemToObject(obj,"type",typeValue);

       cJSON *typeStataValue =   cJSON_CreateNumber(device->stm32_list[i].typeStata);
       cJSON_AddItemToObject(obj,"typeStata",typeStataValue);

       cJSON *valueValue =   cJSON_CreateNumber(device->stm32_list[i].value);
       cJSON_AddItemToObject(obj,"value",valueValue);

       cJSON *floatValueValue =   cJSON_CreateNumber(device->stm32_list[i].floatValue);
       cJSON_AddItemToObject(obj,"floatValue",floatValueValue);

        cJSON_AddItemToArray(stm32Arry,obj);
    }
    cJSON *data_obj = cJSON_CreateObject();
    cJSON_AddItemToObject(data_obj, "data", stm32Arry);
    cJSON *stm32Obj = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "stm32", data_obj);

    // modbus json
    cJSON *modbusArry = cJSON_CreateArray();
    for (size_t i = 0; i < device->modbus_count; i++)

    {


        // {
        //         "key": 2001, //数据点唯一标识(确保数据点表内的唯一性)
        //         "name": "空调模式", //数据点名称(确保单个设备内的唯一性)
        //         "addr": 20011, //模式选择寄存器
        //         "type": 2, //数据点值的类型，1：bool类型 2：int型  3：float型
        //         "value": 11, //11制冷 22制热 33除湿  ⚠️文博注意，slave默认应该为11
        //         "typeStata": 2 // 0只读 1只写 2可读可写
        //     }
            
       cJSON *obj = cJSON_CreateObject();

       cJSON *keyValue =   cJSON_CreateNumber(device->modbus_list[i].key);
       cJSON_AddItemToObject(obj,"key",keyValue);

       cJSON *nameValue =   cJSON_CreateString(device->modbus_list[i].name);
       cJSON_AddItemToObject(obj,"name",nameValue);

       cJSON *typeValue =   cJSON_CreateNumber(device->modbus_list[i].type);
       cJSON_AddItemToObject(obj,"type",typeValue);

       cJSON *typeStataValue =   cJSON_CreateNumber(device->modbus_list[i].typeStata);
       cJSON_AddItemToObject(obj,"typeStata",typeStataValue);

       cJSON *valueValue =   cJSON_CreateNumber(device->modbus_list[i].value);
       cJSON_AddItemToObject(obj,"value",valueValue);

       cJSON *addrValue =   cJSON_CreateNumber(device->modbus_list[i].addr);
       cJSON_AddItemToObject(obj,"addr",addrValue);

    cJSON_AddItemToArray(modbusArry,obj);
    }

    cJSON *modbusData = cJSON_CreateObject();
    cJSON_AddItemToObject(modbusData, "data", modbusArry);
    cJSON *modbusObj = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "modbus", modbusData);

    

    cJSON *metaArry = cJSON_CreateArray();
    for (size_t i = 0; i < device->meta_count; i++)

    {
        // {
        //         "key": 2001, //数据点唯一标识(确保数据点表内的唯一性)
        //         "name": "空调模式", //数据点名称(确保单个设备内的唯一性)
        //         "addr": 20011, //模式选择寄存器
        //         "type": 2, //数据点值的类型，1：bool类型 2：int型  3：float型
        //         "value": 11, //11制冷 22制热 33除湿  ⚠️文博注意，slave默认应该为11
        //         "typeStata": 2 // 0只读 1只写 2可读可写
        //     }
            
       cJSON *obj = cJSON_CreateObject();

       cJSON *keyValue =   cJSON_CreateNumber(device->meta_list[i].key);

       cJSON_AddItemToObject(obj,"key",keyValue);

       cJSON *nameValue =   cJSON_CreateString(device->meta_list[i].name);

       cJSON_AddItemToObject(obj,"name",nameValue);

       cJSON *typeValue =   cJSON_CreateNumber(device->meta_list[i].type);

       cJSON_AddItemToObject(obj,"type",typeValue);

       cJSON *typeStataValue =   cJSON_CreateNumber(device->meta_list[i].typeStata);

       cJSON_AddItemToObject(obj,"typeStata",typeStataValue);

       cJSON *valueValue =   cJSON_CreateNumber(device->meta_list[i].value);
       cJSON_AddItemToObject(obj,"value",valueValue);

       cJSON *addrValue =   cJSON_CreateNumber(device->meta_list[i].addr);
       cJSON_AddItemToObject(obj,"addr",addrValue);

    cJSON_AddItemToArray(metaArry,obj);
    }

    cJSON *metaData = cJSON_CreateObject();
    cJSON_AddItemToObject(metaData, "data", metaArry);
    cJSON *metaObj = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "metaServer", metaData);

    
    
    char *json = cJSON_PrintUnformatted(root);
    printf("%s\n", json);

     
        pubmsg.payload = json;
        pubmsg.payloadlen = strlen(json);
        pubmsg.qos = QOS;
        pubmsg.retained = 0;
        MQTTClient_publishMessage(client, DEVICES_STATA_TOPIC , &pubmsg, &token);

         printf("Waiting for up to %d seconds for publication of %s\n"
               "on topic %s for client with ClientID: %s\n",
               (int)(TIMEOUT / 1000), json, COMMAND_CONTROL_TOPIC, CLIENTID);

        //         rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);

        cJSON_Delete(root);
        free(json);
}
               
   

   // MQTTClient_unsubscribe(client, COMMAND_CONTROL_TOPIC);
   // MQTTClient_disconnect(client, 10000);
    //MQTTClient_destroy(&client);
}

int main()
{

    // 1. 读取点表配置文件
    char *buf = openConfigFile("/home/hq/ShoppingProjec/data-submit-precess/config.json");

    // 2. 解析JSON映射内存结构体
    DeviceData *device = device_data_init(buf);

    free(buf);
    // 释放文件缓冲区
    if (!device)
    {
        return -1;
    }
    

    pthread_t mqtt_thread;

    if (pthread_create(&mqtt_thread, NULL, (void *)startCommitByMQTT, NULL) != 0)
    {
        perror("startCommitByMQTT error");
    };

    pthread_join(mqtt_thread, NULL);

    Stm32Data *first_stm = &device->stm32_list[0];
    printf("stm32 first item: key=%d, name=%s, value=%d\n",
           first_stm->key, first_stm->name, first_stm->value);

    printf("modbus first item: key=%d, name=%s, value=%d\n",
           device->modbus_list[0].key, device->modbus_list[0].name, device->modbus_list[0].value);

    printf("meta first item: key=%d, name=%s, value=%d\n",
           device->meta_list[0].key, device->meta_list[0].name, device->meta_list[0].value);

    // 4. 释放内存
   // device_data_free(device);
    return 0;
}
